home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Stacks.p < prev    next >
Text File  |  1997-05-05  |  59KB  |  2,152 lines

  1. unit Stacks;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  7.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  8.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  9.         QDOffscreen, Timer, PictUtils,
  10.         {Types, Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils,
  11.         Resources, Errors, Palettes, QDOffscreen, PictUtils, Timer, Windows, TextUtils,}
  12.         globals, Utilities, Graphics, Analysis, Camera, file1, file2, filters, sound, lut;
  13.  
  14.     procedure MakeStack;
  15.     procedure MakeWindowsFromStack;
  16.     function AddSlice (update: boolean): boolean;
  17.     procedure DeleteSlice;
  18.     procedure ShowNextSlice (item: integer);
  19.     procedure ShowFirstOrLastSlice (ich: integer);
  20.     procedure DoStackInfo;
  21.     procedure Reslice;
  22.     procedure Animate;
  23.     procedure MakeMovie(ShowDialog: boolean);
  24.     procedure CaptureFrames;
  25.     procedure MakeMontage;
  26.     procedure ConvertRGBToEightBitColor (Capturing: boolean);
  27.     procedure ConvertEightBitColorToRGB;
  28.     procedure CaptureColor;
  29.     procedure AverageSlices(FirstSlice, SliceCount: integer);
  30.     procedure ConvertRGBToHSV;
  31.  
  32.  
  33. implementation
  34.  
  35.  
  36.     procedure MakeStack;
  37.         var
  38.             ok, isStack: boolean;
  39.             i, result: integer;
  40.             TempInfo, SaveInfo: InfoPtr;
  41.             str: str255;
  42.     begin
  43.         if not AllSameSize then begin
  44.                 PutError('All currently open images must be the same size to make a stack.');
  45.                 exit(MakeStack);
  46.             end;
  47.         isStack := false;
  48.         for i := 1 to nPics do begin
  49.                 TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  50.                 isStack := isStack or (TempInfo^.StackInfo <> nil);
  51.             end;
  52.         if isStack then begin
  53.                 PutError('All stacks must be closed before making a new stack.');
  54.                 exit(MakeStack);
  55.             end;
  56.         if nPics > MaxSlices then begin
  57.                 NumToString(MaxSlices, str);
  58.                 PutError(concat('Maximun stack size is ', str, ' slices.'));
  59.                 exit(MakeStack);
  60.             end;
  61.         StopDigitizing;
  62.         DisableDensitySlice;
  63.         SelectWindow(PicWindow[1]);
  64.         Info := pointer(WindowPeek(PicWindow[1])^.RefCon);
  65.         ActivateWindow;
  66.         KillRoi;
  67.         UnZoom;
  68.         if not MakeStackFromWindow then
  69.             exit(MakeStack);
  70.         with info^ do begin
  71.                 StackInfo^.nSlices := nPics;
  72.                 title := 'Stack';
  73.                 UpdateTitleBar;
  74.                 Revertable := false;
  75.             end;
  76.         SaveInfo := Info;
  77.         MakingStack := true;
  78.         ShowWatch;
  79.         for i := 2 to nPics do begin
  80.                 TempInfo := pointer(WindowPeek(PicWindow[2])^.RefCon);
  81.                 with TempInfo^ do begin
  82.                         hunlock(PicBaseHandle);
  83.                         info^.StackInfo^.PicBaseH[i] := PicBaseHandle;
  84.                     end;
  85.                 result := CloseAWindow(PicWindow[2]);
  86.                 Info := SaveInfo;
  87.             end;
  88.         UpdateWindowsMenuItem;
  89.         MakingStack := false;
  90.     end;
  91.  
  92.  
  93.     procedure DeleteSlice;
  94.         var
  95.             SliceToDelete, NextSlice, i: integer;
  96.             isRoi: boolean;
  97.     begin
  98.         with info^, info^.StackInfo^ do begin
  99.                 if nSlices = 1 then begin
  100.                         WhatToUndo := NothingToUndo;
  101.                         exit(DeleteSlice);
  102.                     end;
  103.                 isRoi := RoiShowing;
  104.                 if isRoi then
  105.                     KillRoi;
  106.                 SetupUndo;
  107.                 WhatToUndo := UndoSliceDelete;
  108.                 SliceToDelete := CurrentSlice;
  109.                 if CurrentSlice = 1 then begin
  110.                         NextSlice := 2;
  111.                         WhatToUndo := UndoFirstSliceDelete;
  112.                     end
  113.                 else
  114.                     NextSlice := CurrentSlice - 1;
  115.                 SelectSlice(NextSlice);
  116.                 UpdatePicWindow;
  117.                 DisposeHandle(PicBaseH[SliceToDelete]);
  118.                 for i := SliceToDelete to nSlices - 1 do
  119.                     PicBaseH[i] := PicBaseH[i + 1];
  120.                 nSlices := nSlices - 1;
  121.                 if CurrentSlice <> 1 then
  122.                     CurrentSlice := CurrentSlice - 1;
  123.                 if (StackType = rgbStack) and (nSlices <> 3) then
  124.                     StackType := VolumeStack;
  125.                 UpdateTitleBar;
  126.                 if isRoi then
  127.                     RestoreRoi;
  128.                 changes := true;
  129.                 UpdateWindowsMenuItem;
  130.             end;
  131.     end;
  132.  
  133.  
  134.     procedure MakeWindowsFromStack;
  135.         var
  136.             i, ignore: integer;
  137.             N: LongInt;
  138.             SaveInfo: InfoPtr;
  139.             tmp: longint;
  140.  
  141.         function MakeName (i: integer): str255;
  142.             var
  143.                 str: str255;
  144.         begin
  145.             RealToString(i, 3, 0, str);
  146.             if str[1] = ' ' then
  147.                 str[1] := '0';
  148.             if str[2] = ' ' then
  149.                 str[2] := '0';
  150.             MakeName := str;
  151.         end;
  152.  
  153.     begin
  154.         N := info^.StackInfo^.nSlices;
  155.         tmp := SizeOf(PicInfo);
  156.         if MaxBlock < (MinFree + info^.ImageSize + (SizeOf(PicInfo) + 2000) * N) then begin
  157.                 PutError('There is not enough memory available to convert this stack to windows.');
  158.                 exit(MakeWindowsFromStack);
  159.             end;
  160.         SaveInfo := Info;
  161.         KillRoi;
  162.         for i := 1 to N - 1 do begin
  163.                 SelectSlice(1);
  164.                 info^.StackInfo^.CurrentSlice := 1;
  165.                 if not Duplicate(MakeName(i), false) then
  166.                     exit(MakeWindowsFromStack);
  167.                 info := SaveInfo;
  168.                 DeleteSlice;
  169.             end;
  170.         if Duplicate(MakeName(N), false) then begin
  171.                 info := SaveInfo;
  172.                 info^.changes := false;
  173.                 ignore := CloseAWindow(info^.wptr);
  174.             end;
  175.     end;
  176.  
  177.  
  178.     procedure ShowNextSlice (item: integer);
  179.         var
  180.             isRoi: boolean;
  181.     begin
  182.         with info^, info^.StackInfo^ do begin
  183.                 if item = NextSliceItem then begin
  184.                         CurrentSlice := CurrentSlice + 1;
  185.                         if CurrentSlice > nSlices then
  186.                             CurrentSlice := nSlices;
  187.                     end
  188.                 else begin
  189.                         CurrentSlice := CurrentSlice - 1;
  190.                         if CurrentSlice < 1 then
  191.                             CurrentSlice := 1;
  192.                     end;
  193.                 isRoi := RoiShowing;
  194.                 if isRoi then
  195.                     KillRoi;
  196.                 SelectSlice(CurrentSlice);
  197.                 UpdatePicWindow;
  198.                 UpdateTitleBar;
  199.                 WhatToUndo := NothingToUndo;
  200.                 isInsertionPoint:=false;
  201.                 if isRoi then
  202.                     RestoreRoi;
  203.             end;
  204.     end;
  205.  
  206.  
  207.     procedure ShowFirstOrLastSlice (ich: integer);
  208.         var
  209.             isRoi: boolean;
  210.     begin
  211.         with info^, info^.StackInfo^ do begin
  212.                 if ich = EndKey then
  213.                     CurrentSlice := nSlices
  214.                 else
  215.                     CurrentSlice := 1;
  216.                 isRoi := RoiShowing;
  217.                 if isRoi then
  218.                     KillRoi;
  219.                 SelectSlice(CurrentSlice);
  220.                 UpdatePicWindow;
  221.                 UpdateTitleBar;
  222.                 WhatToUndo := NothingToUndo;
  223.                 isInsertionPoint:=false;
  224.                 if isRoi then
  225.                     RestoreRoi;
  226.             end;
  227.     end;
  228.  
  229.  
  230.     procedure GetSlice (xstart, ystart, start: extended; angle: extended; count: integer; var line: LineType);
  231.         var
  232.             i: integer;
  233.             x, y, xinc, yinc: extended;
  234.             IntegerStart: boolean;
  235.     begin
  236.         IntegerStart := (xstart = trunc(xstart)) and (ystart = trunc(ystart));
  237.         if IntegerStart and (angle = 0.0) then begin
  238.                 GetLine(trunc(xstart), trunc(ystart), count, line);
  239.                 exit(GetSlice);
  240.             end;
  241.         if IntegerStart and (angle = 270.0) then begin
  242.                 GetColumn(trunc(xstart), trunc(ystart), count, line);
  243.                 exit(GetSlice);
  244.             end;
  245.         angle := (angle / 180.0) * pi;
  246.         xinc := cos(angle);
  247.         yinc := -sin(angle);
  248.         x := xstart + start * xinc;
  249.         y := ystart + start * yinc;
  250.         for i := 0 to count - 1 do begin
  251.                 line[i] := round(GetInterpolatedPixel(x, y));
  252.                 x := x + xinc;
  253.                 y := y + yinc;
  254.             end;
  255.     end;
  256.  
  257.  
  258.     function DoResliceOptions: boolean;
  259.     var
  260.         default, tmp: extended;
  261.         Canceled: boolean;
  262.         prompt, str: str255;
  263.     begin
  264.         with info^.StackInfo^, info^ do begin
  265.             if SpatiallyCalibrated then begin
  266.                 default := SliceSpacing / xScale;
  267.                 str := xUnit;
  268.             end else begin
  269.                 default := SliceSpacing;
  270.                 str := 'pixels';
  271.             end;
  272.             if SliceSpacing = 0.0 then
  273.                 default := 1.0;
  274.             tmp := GetReal(concat('Slice Spacing (', str, '):'), default, 2, Canceled);
  275.             if not Canceled and (tmp > 0.0) then begin
  276.                     if SpatiallyCalibrated then
  277.                         SliceSpacing := tmp * xScale
  278.                     else
  279.                         SliceSpacing := tmp;
  280.                 end;
  281.         end; {with}
  282.         DoResliceOptions := not canceled;
  283.     end;
  284.  
  285.  
  286.     procedure Reslice;
  287.         var
  288.             DstWidth, DstHeight, nSlices: integer;
  289.             dstLeft, dstTop, y, i, j, LineLength: integer;
  290.             SaveWindowFlag, SaveMacro, HorizontalMode: boolean;
  291.             SaveHScale, SaveVScale, UncalibratedLineLength, CalibratedLineLength, angle: extended;
  292.             Stack, Reconstruction: InfoPtr;
  293.             aLine: LineType;
  294.             name, str1, str2: str255;
  295.             MaskRect: rect;
  296.             x1, y1, x2, y2, ulength, clength: extended;
  297.  
  298.         procedure MakeRoi (Left, Top, Width, Height: integer);
  299.         begin
  300.             with info^ do begin
  301.                     RoiType := RectRoi;
  302.                     SetRect(RoiRect, left, top, left + width, top + height);
  303.                     MakeRegion;
  304.                     SetupUndo;
  305.                     RoiShowing := true;
  306.                 end;
  307.         end;
  308.  
  309.     begin
  310.         with info^, info^.StackInfo^ do begin
  311.                 if nSlices < 2 then begin
  312.                         PutError('Reslicing requires at least 2 slices.');
  313.                         AbortMacro;
  314.                         exit(Reslice);
  315.                     end;
  316.                 if not (RoiShowing and (RoiType = LineRoi)) then begin
  317.                         PutError('Please make a straight line selection first.');
  318.                         AbortMacro;
  319.                         exit(Reslice);
  320.                     end;
  321.                 Stack := info;
  322.                 GetLengthOrPerimeter(ulength, clength);
  323.                 LineLength := round(ulength);
  324.                 if LineLength = 0 then begin
  325.                         PutError('Line length cannot be zero.');
  326.                         AbortMacro;
  327.                         exit(Reslice);
  328.                     end;
  329.                 if SliceSpacing = 0.0 then
  330.                     if not DoResliceOptions then
  331.                         exit(reslice);;
  332.                 GetLoi(x1, y1, x2, y2);
  333.                 if (LAngle = 0.0) or (LAngle = 270.0) then
  334.                     if NotInBounds then
  335.                         exit(Reslice);
  336.                 HorizontalMode := not OptionKeyWasDown;
  337.                 if HorizontalMode then begin
  338.                         DstWidth := LineLength;
  339.                         DstHeight := round(nSlices * SliceSpacing);
  340.                         if DstHeight < nSlices then
  341.                             DstHeight := nSlices;
  342.                         dstLeft := 0;
  343.                         dstTop := round((dstHeight - nSlices) / 2.0);
  344.                     end
  345.                 else begin
  346.                         DstWidth := round(nSlices * SliceSpacing);
  347.                         if DstWidth < nSlices then
  348.                             DstWidth := nSlices;
  349.                         DstHeight := LineLength;
  350.                         dstLeft := round((dstWidth - nSlices) / 2.0);
  351.                         dstTop := 0;
  352.                     end;
  353.                 RealToString(y1, 3, 0, str1);
  354.                 RealToString(LAngle, 1, 2, str2);
  355.                 name := concat(str1, '-', str2);
  356.                 if not NewPicWindow(name, DstWidth, DstHeight) then
  357.                     exit(Reslice);
  358.                 Reconstruction := info;
  359.                 SaveWindowFlag := rsCreateNewWindow;
  360.                 SaveHScale := rsHScale;
  361.                 SaveVScale := rsVScale;
  362.                 rsCreateNewWindow := false;
  363.                 rsMethod := bilinear;
  364.                 for i := 1 to nSlices do begin
  365.                         Info := Stack;
  366.                         SelectSlice(i);
  367.                         GetSlice(x1, y1, 0.0, LAngle, LineLength, aLine);
  368.                         info := Reconstruction;
  369.                         if HorizontalMode then begin
  370.                                 PutLine(dstLeft, dstTop + nSlices - i, LineLength, aLine);
  371.                                 if i = 1 then {Draw extra line needed to get scaling to work right.}
  372.                                     PutLine(dstLeft, dstTop + nSlices, LineLength, aLine);
  373.                                 SetRect(MaskRect, dstLeft, dstTop + nSlices - i, dstLeft + LineLength, dstTop + nSlices - i + 1);
  374.                             end
  375.                         else begin
  376.                                 PutColumn(dstLeft + nSlices - i, dstTop, LineLength, aLine);
  377.                                 if i = 1 then {Draw extra line needed to get scaling to work right.}
  378.                                     PutLine(dstLeft + nSlices, dstTop, LineLength, aLine);
  379.                                 SetRect(MaskRect, dstLeft + nSlices - i, dstTop, dstLeft + nSlices - i + 1, dstTop + LineLength);
  380.                             end;
  381.                         UpdateScreen(MaskRect);
  382.                     end;
  383.                 if HorizontalMode then begin
  384.                         MakeRoi(dstLeft, dstTop, LineLength, nSlices);
  385.                         rsHScale := 1.0;
  386.                         rsVScale := SliceSpacing;
  387.                     end
  388.                 else begin
  389.                         MakeRoi(dstLeft, dstTop, nSlices, LineLength);
  390.                         rsHScale := SliceSpacing;
  391.                         rsVScale := 1.0;
  392.                     end;
  393.                 rsAngle := 0;
  394.                 SaveMacro := macro;
  395.                 macro := true;
  396.                 ScaleAndRotate;
  397.                 macro := SaveMacro;
  398.                 Info := Stack;
  399.                 SelectSlice(CurrentSlice);
  400.                 Info := Reconstruction;
  401.                 rsCreateNewWindow := SaveWindowFlag;
  402.                 rsHScale := SaveHScale;
  403.                 rsVScale := SaveVScale;
  404.                 KillRoi;
  405.             end;
  406.     end;
  407.  
  408.  
  409.     procedure Animate;
  410.         var
  411.             n, SaveN, fpsInterval, DelayCount: integer;
  412.             Event: EventRecord;
  413.             ch: char;
  414.             b: boolean;
  415.             SingleStep, GoForward, NewKeyDown, PhotoMode: boolean;
  416.             nFrames, StartTicks, NextTicks, SaveTicks, ticks: LongInt;
  417.             fps, seconds: extended;
  418.  
  419.         procedure ShowFPS (fps: extended);
  420.             var
  421.                 hstart, vstart, ivalue: integer;
  422.                 key: str255;
  423.         begin
  424.             if PhotoMode then
  425.                 exit(ShowFPS);
  426.             hstart := InfoHStart;
  427.             vstart := InfoVStart;
  428.             SetPort(InfoWindow);
  429.             MoveTo(xValueLoc, vstart);
  430.             case DelayTicks of
  431.                 0: 
  432.                     key := '9 ';
  433.                 2: 
  434.                     key := '8 ';
  435.                 3: 
  436.                     key := '7 ';
  437.                 4: 
  438.                     key := '6 ';
  439.                 6: 
  440.                     key := '5 ';
  441.                 8: 
  442.                     key := '4 ';
  443.                 12: 
  444.                     key := '3 ';
  445.                 30: 
  446.                     key := '2 ';
  447.                 60: 
  448.                     key := '1 ';
  449.             end;
  450.             if SingleStep then begin
  451.                     if GoForward then
  452.                         key := '->'
  453.                     else
  454.                         key := '<-';
  455.                 end;
  456.             DrawString(key);
  457.             MoveTo(yValueLoc, vstart + 10);
  458.             DrawReal(fps, 1, 2);
  459.             DrawChar(' ');
  460.         end;
  461.  
  462.     begin
  463.         if info^.StackInfo = nil then begin
  464.                 PutError('Animation requires a stack.');
  465.                 exit(Animate);
  466.             end;
  467.         with info^, info^.StackInfo^ do begin
  468.                 if nSlices < 2 then begin
  469.                         PutError('Animation requires at least two "slices".');
  470.                         exit(Animate);
  471.                     end;
  472.                 KillRoi;
  473.                 PhotoMode := OptionKeyDown or OptionKeyWasDown;
  474.                 if PhotoMode then
  475.                     EraseScreen
  476.                 else begin
  477.                         ShowWatch;
  478.                         ShowMessage(concat('Use 1...9 keys to control speed', crStr, 'Use arrow keys to single step', crStr, 'Press mouse button to stop'));
  479.                     end;
  480.                 FlushEvents(EveryEvent, 0);
  481.                 fpsInterval := 10;
  482.                 SaveN := -1;
  483.                 n := 1;
  484.                 GoForward := true;
  485.                 SingleStep := false;
  486.                 nFrames := 0;
  487.                 StartTicks := TickCount;
  488.                 NextTicks := StartTicks;
  489.                 SaveTicks := StartTicks;
  490.                 if not PhotoMode then begin
  491.                         DrawLabels('key:', 'fps:', '');
  492.                         SetPort(InfoWindow);
  493.                         TextSize(9);
  494.                         TextFont(Monaco);
  495.                         TextMode(SrcCopy);
  496.                     end;
  497.                 repeat
  498.                     b := WaitNextEvent(EveryEvent, Event, 0, nil);
  499.                     NewKeyDown := (event.what = KeyDown) or (event.what = AutoKey);
  500.                     if NewKeyDown then begin
  501.                             Ch := chr(BitAnd(Event.message, 127));
  502.                             SingleStep := false;
  503.                             case ord(ch) of
  504.                                 28, 44, 60, PageUp: {<-, <}
  505.                                     begin
  506.                                         SingleStep := true;
  507.                                         GoForward := false;
  508.                                         n := n - 1;
  509.                                         if n < 1 then
  510.                                             n := 1;
  511.                                         DelayTicks := 0
  512.                                     end; {left}
  513.                                 29, 46, 62, PageDown:  {->, >}
  514.                                     begin
  515.                                         SingleStep := true;
  516.                                         GoForward := true;
  517.                                         n := n + 1;
  518.                                         if n > nSlices then
  519.                                             n := nSlices;
  520.                                         DelayTicks := 0
  521.                                     end;  {right}
  522.                                 57: 
  523.                                     DelayTicks := 0;  {'9'-max speed}
  524.                                 56: 
  525.                                     DelayTicks := 2;  {'8'-30 fps}
  526.                                 55: 
  527.                                     DelayTicks := 3;  {'7'-20 fps}
  528.                                 54: 
  529.                                     DelayTicks := 4;  {'6'-15 fps}
  530.                                 53: 
  531.                                     DelayTicks := 6;  {'5'-10 fps}
  532.                                 52: 
  533.                                     DelayTicks := 8; {'4'-7.5 fps}
  534.                                 51: 
  535.                                     DelayTicks := 12; {'3'-5 fps}
  536.                                 50: 
  537.                                     DelayTicks := 30; {'2'-2 fps}
  538.                                 49: 
  539.                                     DelayTicks := 60; {'1'-1 fps}
  540.                                 otherwise
  541.                             end; {case}
  542.                             if DelayTicks > 12 then
  543.                                 fpsInterval := 2
  544.                             else if DelayTicks > 3 then
  545.                                 fpsInterval := 5
  546.                             else
  547.                                 fpsInterval := 10;
  548.                         end; {if NewKeyDown}
  549.                     if GoForward then begin
  550.                             if not SingleStep then
  551.                                 n := n + 1;
  552.                             if n > nSlices then begin
  553.                                     if OscillatingMovies then begin
  554.                                             n := nSlices - 1;
  555.                                             GoForward := false;
  556.                                         end
  557.                                     else
  558.                                         n := 1;
  559.                                 end;
  560.                         end
  561.                     else begin
  562.                             if not SingleStep then
  563.                                 n := n - 1;
  564.                             if n < 1 then begin
  565.                                     if OscillatingMovies then begin
  566.                                             n := 2;
  567.                                             Goforward := true;
  568.                                         end
  569.                                     else
  570.                                         n := nSlices;
  571.                                 end;
  572.                         end;
  573.                     CurrentSlice := n;
  574.                     SelectSlice(CurrentSlice);
  575.                     UpdatePicWindow;
  576.                     nFrames := nFrames + 1;
  577.                     if SingleStep then begin
  578.                             if (not OptionKeyWasDown) and (n <> SaveN) then begin
  579.                                     UpdateTitleBar;
  580.                                     SaveN := n;
  581.                                 end;
  582.                             ShowFPS(0.0);
  583.                         end
  584.                     else if (nFrames mod fpsInterval) = 0 then begin
  585.                             ticks := TickCount;
  586.                             seconds := (ticks - SaveTicks) / 60.0;
  587.                             if seconds <> 0.0 then
  588.                                 fps := fpsInterval / seconds
  589.                             else
  590.                                 fps := 0.0;
  591.                             ShowFPS(fps);
  592.                             SaveTicks := ticks;
  593.                         end;
  594.                     DelayCount := 0;
  595.                     if DelayTicks > 0 then begin
  596.                             repeat
  597.                                 ticks := TickCount;
  598.                             until ticks >= NextTicks;
  599.                             NextTicks := ticks + DelayTicks;
  600.                         end;
  601.                 until (event.what = MouseDown) or (event.what = osEvt);
  602.                 if PhotoMode then
  603.                     RestoreScreen;
  604.                 FlushEvents(EveryEvent, 0);
  605.                 UpdateTitleBar
  606.             end; {with}
  607.     end;
  608.  
  609.  
  610.     function Activate (name: str255): boolean;
  611.   {Activates the window with the specified name.}
  612.         var
  613.             i: integer;
  614.             TempInfo: InfoPtr;
  615.     begin
  616.         Activate := false;
  617.         for i := 1 to nPics do begin
  618.                 TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  619.                 if TempInfo^.title = name then begin
  620.                         if PicWindow[i] <> nil then begin
  621.                                 SelectWindow(PicWindow[i]);
  622.                                 Info := TempInfo;
  623.                                 ActivateWindow;
  624.                                 Activate := true;
  625.                             end; {if}
  626.                         leave;
  627.                     end; {if}
  628.             end; {for}
  629.     end;
  630.  
  631.  
  632.     function DoMakeMovieOptions: boolean;
  633.     const
  634.         FramesID = 3;
  635.         IntervalID = 5;
  636.         rateID = 7;
  637.         BlindID = 9;
  638.         LG3BufferID = 10;
  639.         StampID = 11;
  640.         UseExistingStackID = 12;
  641.         TriggerID = 13;
  642.         TriggerFirstID = 14;
  643.         TriggerEachID = 15;
  644.     var
  645.         mylog: DialogPtr;
  646.         item, i: integer;
  647.         FramesPerSecond: extended;
  648.         
  649.         procedure ShowFrameRate;
  650.         begin
  651.             if SecondsPerFrame = 0.0 then begin
  652.                 if fgWidth = 640 then
  653.                     FramesPerSecond := 30.0
  654.                 else FramesPerSecond := 25.0
  655.             end else
  656.                 FramesPerSecond := 1.0 / SecondsPerFrame;
  657.             if FramesPerSecond = trunc(FramesPerSecond) then
  658.                 SetDReal(MyLog, rateID, FramesPerSecond, 0)
  659.             else
  660.                 SetDReal(MyLog, rateID, FramesPerSecond, 4);
  661.         end;
  662.         
  663.         procedure ShowInterval;
  664.         begin
  665.             if SecondsPerFrame < 1.0 then
  666.                 SetDReal(MyLog, IntervalID, SecondsPerFrame, 4)
  667.             else if SecondsPerFrame < 99.0 then
  668.                 SetDReal(MyLog, IntervalID, SecondsPerFrame, 2)
  669.             else
  670.                 SetDReal(MyLog, IntervalID, SecondsPerFrame, 0);
  671.         end;
  672.         
  673.         procedure ShowTriggerMode;
  674.         begin
  675.             SetDlogItem(mylog, TriggerID, ord(ExternalTrigger));
  676.             SetDlogItem(mylog, TriggerFirstID, ord(TriggerFirstFrameOnly));
  677.             SetDlogItem(mylog, TriggerEachID, ord(not TriggerFirstFrameOnly));
  678.         end;
  679.         
  680.     begin
  681.         InitCursor;
  682.         mylog := GetNewDialog(230, nil, pointer(-1));
  683.         SetDNum(MyLog, FramesID, FramesWanted);
  684.         ShowFrameRate;
  685.         ShowInterval;
  686.         SetDlogItem(mylog, BlindID, ord(BlindMovieCapture));
  687.         SetDlogItem(mylog, LG3BufferID, ord(LG3BufferCapture));
  688.         SetDlogItem(mylog, StampID, ord(TimeStamp));
  689.         ShowTriggerMode;
  690.         SetDlogItem(mylog, UseExistingStackID, ord(UseExistingStack));
  691.         SelectDialogItemText(MyLog, FramesID, 0, 32767);
  692.         OutlineButton(MyLog, ok, 16);
  693.         repeat
  694.             ModalDialog(nil, item);
  695.             if item = FramesID then
  696.                 FramesWanted := GetDNum(MyLog, FramesID);
  697.             if item = IntervalID then begin
  698.                 SecondsPerFrame := GetDReal(MyLog, IntervalID);
  699.                 ShowFrameRate;
  700.             end;
  701.             if item = rateID then begin
  702.                 FramesPerSecond := GetDReal(MyLog, rateID);
  703.                 if FramesPerSecond <> 0.0 then
  704.                   SecondsPerFrame := 1.0 / FramesPerSecond;
  705.                 ShowInterval;
  706.             end;
  707.             if item = BlindID then begin
  708.                     BlindMovieCapture := not BlindMovieCapture;
  709.                     SetDlogItem(mylog, BlindID, ord(BlindMovieCapture));
  710.                 end;
  711.             if item = LG3BufferID then begin
  712.                     LG3BufferCapture := not LG3BufferCapture;
  713.                     if LG3BufferCapture then
  714.                         BlindMovieCapture := true;
  715.                     SetDlogItem(mylog, LG3BufferID, ord(LG3BufferCapture));
  716.                     SetDlogItem(mylog, BlindID, ord(BlindMovieCapture));
  717.                 end;
  718.             if item = StampID then begin
  719.                     TimeStamp := not TimeStamp;
  720.                     SetDlogItem(mylog, StampID, ord(TimeStamp));
  721.                 end;
  722.             if item = TriggerID then begin
  723.                 ExternalTrigger := not ExternalTrigger;
  724.                 SetDlogItem (mylog, TriggerID, ord (ExternalTrigger));
  725.               end;
  726.             if (item = TriggerFirstID) or (item = TriggerEachID) then begin
  727.                 TriggerFirstFrameOnly := not TriggerFirstFrameOnly;
  728.                 ExternalTrigger := true;
  729.                 ShowTriggerMode;
  730.               end;
  731.             if item = UseExistingStackID then begin
  732.                     UseExistingStack := not UseExistingStack;
  733.                     SetDlogItem(mylog, UseExistingStackID, ord(UseExistingStack));
  734.                 end;
  735.         until (item = ok) or (item = cancel);
  736.         DisposeDialog(mylog);
  737.         if FramesWanted < 1 then
  738.             FramesWanted := 1;
  739.         if FramesWanted > MaxSlices then
  740.             FramesWanted := MaxSlices;
  741.         if SecondsPerFrame < 0.0 then
  742.             SecondsPerFrame := 0.0;
  743.         if LG3BufferCapture and (item <> cancel) then begin
  744.             if FrameGrabber <> ScionLG3 then begin
  745.                 LG3BufferCapture := false;
  746.                 PutError('Capturing to an on-board frame buffer requires a Scion LG-3.');
  747.                 DoMakeMovieOptions := false;
  748.                 exit(DoMakeMovieOptions);
  749.             end;
  750.             if PCIFrameGrabber then begin
  751.                 LG3BufferCapture := false;
  752.                 PutError('On-board capture not supported on PCI frame grabbers.');
  753.                 DoMakeMovieOptions := false;
  754.                 exit(DoMakeMovieOptions);
  755.             end;
  756.             if FramesWanted > MaxLG3Frames then begin
  757.                 FramesWanted := MaxLG3Frames;
  758.                 PutError(concat('This ', long2str(MaxLG3Frames div 2), 'MB LG-3 can capture a maximum of ', long2str(MaxLG3Frames), ' frames to its on-board buffer.'));
  759.                 DoMakeMovieOptions := false;
  760.                 exit(DoMakeMovieOptions);
  761.             end;
  762.         end;
  763.         DoMakeMovieOptions := item <> cancel;
  764.     end;
  765.  
  766.  
  767.     procedure CaptureFramesUsingTicks(SecondsPerFrame:extended; nFrames:integer; frect:rect);
  768.     var
  769.         StartTicks, NextTicks, LastTicks, interval, ticks: LongInt;
  770.         SourcePixMap: PixMapHandle;
  771.         str: str255;
  772.         frame, i: integer;
  773.         ElapsedTime, avgFrameInterval: extended;
  774.     begin
  775.         interval := round(60.0 * SecondsPerFrame);
  776.         ShowWatch;
  777.         SourcePixMap := fgPixMap;
  778.         ResetFrameGrabber;
  779.         ShowTriggerMessage;
  780.         with info^, info^.StackInfo^ do begin
  781.                 if Interval >= 30 then
  782.                     ShowMessage(CmdPeriodToStop)
  783.                 else
  784.                     DrawLabels('Frame:', 'Total:', '');
  785.                 if TimeStamp then begin
  786.                     SetPort(GrafPtr(osPort));
  787.                     TextFont(Monaco);
  788.                     TextSize(9);
  789.                 end;
  790.                 for frame := 1 to nFrames do begin
  791.                         CurrentSlice := frame;
  792.                         SelectSlice(CurrentSlice);
  793.                         if Interval >= 30 then
  794.                             UpdateTitleBar
  795.                         else
  796.                             Show2Values(CurrentSlice, nSlices);
  797.                         GetFrame;
  798.                         ticks:=TickCount;
  799.                         if (frame = 1) then begin
  800.                             StartTicks := ticks;
  801.                             NextTicks := StartTicks+interval - 3;
  802.                             if TriggerFirstFrameOnly then
  803.                                 ExternalTrigger := false;
  804.                         end else
  805.                             NextTicks := NextTicks + interval;
  806.                         if frame = nFrames then
  807.                             LastTicks := ticks;
  808.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  809.                         if TimeStamp then begin
  810.                             ElapsedTime:=(ticks-StartTicks) / 60.0;
  811.                             RealToString(ElapsedTime, 9, 3, str);
  812.                             for i:=1 to 5 do
  813.                                 if str[i]=' ' then str[i]:='0';
  814.                             MoveTo(2,10);
  815.                             DrawString(str);
  816.                             PlotData^[frame]:=ElapsedTime;
  817.                         end;
  818.                         if not BlindMovieCapture then
  819.                             UpdatePicWindow;
  820.                         while TickCount < NextTicks do
  821.                             if CommandPeriod then begin
  822.                                     beep;
  823.                                     wait(60);
  824.                                     exit(CaptureFramesUsingTicks);
  825.                                 end;
  826.                     end; {for}
  827.                 ElapsedTime := (LastTicks - StartTicks) / 60.0;
  828.                 avgFrameInterval := ElapsedTime / (nFrames - 1);
  829.                 FrameInterval := avgFrameInterval;
  830.             end; {with}
  831.     end;
  832.  
  833.  
  834.  
  835.     procedure DrawTimeStamps(nFrames: integer);
  836.     var
  837.         frame, i: integer;
  838.         str: str255;
  839.         SaveGDevice: GDHandle;
  840.     begin
  841.         with info^, info^.StackInfo^ do begin
  842.             SaveGDevice := GetGDevice;
  843.             SetGDevice(osGDevice);
  844.             SetPort(GrafPtr(osPort));
  845.             TextFont(Monaco);
  846.             TextSize(9);
  847.             for frame := 1 to nFrames do begin
  848.                 ShowAnimatedWatch;
  849.                 CurrentSlice := frame;
  850.                 SelectSlice(CurrentSlice);
  851.                 RealToString(PlotData^[frame], 9, 3, str);
  852.                 for i:=1 to 5 do
  853.                     if str[i]=' ' then str[i]:='0';
  854.                 MoveTo(2,10);
  855.                 DrawString(str);
  856.             end; {for}
  857.             SetGDevice(SaveGDevice);
  858.         end;
  859.     end;
  860.  
  861.  
  862.     function uTickCount:extended;
  863.     var
  864.         count:UnsignedWide;
  865.         d:extended;
  866.     begin
  867.         microseconds(count);
  868.         d:=count.lo;
  869.         if d<0 then d:=band(count.lo,$7fffffff)+2147483648.0;
  870.         uTickCount:=d+count.hi*4294967296.0;
  871.     end;
  872.  
  873.  
  874.     procedure CaptureFramesUsingMicroTicks(SecondsPerFrame:extended; nFrames:integer; frect:rect);
  875.     var
  876.         uStartTicks, uNextTicks, uLastTicks, uInterval, uTicks: Extended;
  877.         SourcePixMap: PixMapHandle;
  878.         frame, i: integer;
  879.         ElapsedTime: extended;
  880.         uTicksToCaptureOneFrame, avgFrameInterval:extended;
  881.         ShowProgress: boolean;
  882.     begin
  883.         ShowWatch;
  884.         uInterval := 1000000.0 * SecondsPerFrame;
  885.         SourcePixMap := fgPixMap;
  886.         ResetFrameGrabber;
  887.         if PCIFrameGrabber then begin
  888.             DoubleBuffering := true;
  889.             LG3BufferCapture := false;
  890.             CurrentBufferIsZero := true;
  891.         end;
  892.         ShowTriggerMessage;
  893.         if fgWidth = 768 then  {if PAL board}
  894.             uTicksToCaptureOneFrame := 40000.0  {PAL captures 25 fps}
  895.         else
  896.             uTicksToCaptureOneFrame := 33333.0;  {non-PAL captures 33 fps}
  897.         ShowProgress := ((not LG3BufferCapture) and (not DoubleBuffering)) or (uInterval > (2 * uTicksToCaptureOneFrame));
  898.         with info^, info^.StackInfo^ do begin
  899.                 if ShowProgress and (uInterval < 500000.0) then
  900.                     DrawLabels('Frame:', 'Total:', '')
  901.                 else if not ExternalTrigger then
  902.                     ShowMessage(CmdPeriodToStop);
  903.                 for frame := 1 to nFrames do begin
  904.                     CurrentSlice := frame;
  905.                     if DoubleBuffering and (frame > 1) then {??}
  906.                         SelectSlice(CurrentSlice - 1)
  907.                     else
  908.                         SelectSlice(CurrentSlice);
  909.                     if showProgress then begin
  910.                         if uInterval >= 500000.0 then
  911.                             UpdateTitleBar
  912.                         else
  913.                             Show2Values(CurrentSlice, nSlices);
  914.                     end;
  915.                     if DoubleBuffering then begin
  916.                         StartFrame;
  917.                         if frame <> 1 then
  918.                             CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  919.                         StopFrame;
  920.                         uTicks := uTickCount;
  921.                     end else if LG3BufferCapture then begin
  922.                         BufferReg^ := frame - 1;
  923.                         GetFrame;
  924.                         uTicks := uTickCount;
  925.                     end else begin
  926.                         GetFrame;
  927.                         uTicks := uTickCount;
  928.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  929.                     end;
  930.                     if frame = 1 then begin
  931.                         uStartTicks := uTicks;
  932.                         uNextTicks := uStartTicks + uInterval - 1.5 * uTicksToCaptureOneFrame;
  933.                         if TriggerFirstFrameOnly then
  934.                             ExternalTrigger := false;
  935.                     end else
  936.                         uNextTicks :=uNextTicks + uInterval;
  937.                     if frame = nFrames then
  938.                         uLastTicks := uTicks;
  939.                     if TimeStamp then begin
  940.                         ElapsedTime:=(uTicks-uStartTicks) / 1000000.0;
  941.                         PlotData^[frame]:=ElapsedTime;
  942.                     end;
  943.                     if not BlindMovieCapture then
  944.                         UpdatePicWindow;
  945.                     if uTicks < uNextTicks then
  946.                         while uTickCount < uNextTicks do
  947.                             if CommandPeriod then begin
  948.                                     beep;
  949.                                     wait(60);
  950.                                     exit(CaptureFramesUsingMicroTicks);
  951.                                 end;
  952.                     end; {for}
  953.                 ElapsedTime := (uLastTicks - uStartTicks) / 1000000.0;
  954.                 avgFrameInterval := ElapsedTime / (nFrames - 1);
  955.                 FrameInterval := avgFrameInterval;
  956.             end; {with}
  957.         if LG3BufferCapture then begin
  958.             {Copy captured frames from LG-3 to stack.}
  959.             with info^, info^.StackInfo^ do begin
  960.                 for frame := 1 to nFrames do begin
  961.                     ShowAnimatedWatch;
  962.                     CurrentSlice := frame;
  963.                     SelectSlice(CurrentSlice);
  964.                     BufferReg^ := frame - 1;
  965.                     CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  966.                 end; {for}
  967.             end; {with}
  968.             BufferReg^ := 0;
  969.         end; {if LG3BufferCapture}
  970.         if DoubleBuffering then with info^, info^.StackInfo^ do begin
  971.             CurrentSlice := nframes;
  972.             SelectSlice(CurrentSlice);
  973.             CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  974.             BufferReg^ := 0;
  975.             CurrentBufferIsZero := true;
  976.             DoubleBuffering := false;
  977.             with fgPort^.PortPixMap^^ do
  978.                 BaseAddr := ptr(fgSuperSlotBase0);
  979.         end;
  980.         if TimeStamp then
  981.             DrawTimeStamps(nFrames);
  982.     end;
  983.  
  984.     
  985.     
  986.     procedure MakeMovie(ShowDialog: boolean);
  987.         var
  988.             nFrames, wleft, wtop, width, height: integer;
  989.             ignore, SaveFW: integer;
  990.             OutOfMemory: boolean;
  991.             seconds: extended;
  992.             frect: rect;
  993.             Canceled: boolean;
  994.             avgFrameInterval: extended;
  995.     begin
  996.         SelectCameraWindow;
  997.         with info^ do begin
  998.             if PictureType <> FrameGrabberType then begin
  999.                     PutError('You must be capturing to make a movie.');
  1000.                     exit(MakeMovie);
  1001.                 end;
  1002.             StopDigitizing;
  1003.             if not (RoiShowing and (RoiType = RectRoi)) then begin
  1004.                     PutError('Please make a rectangular selection first.');
  1005.                     exit(MakeMovie);
  1006.                 end;
  1007.             if NotInBounds then
  1008.                 exit(MakeMovie);
  1009.             if ShowDialog then
  1010.                 if not DoMakeMovieOptions then begin
  1011.                     AbortMacro;
  1012.                     exit(MakeMovie);
  1013.                 end;
  1014.             if (FrameGrabber <> ScionLG3) then
  1015.                 LG3BufferCapture := false;
  1016.             if LG3BufferCapture and (FramesWanted > MaxLG3Frames) then
  1017.                 FramesWanted := MaxLG3Frames;
  1018.             if LG3BufferCapture then
  1019.                 BlindMovieCapture := true;
  1020.             with RoiRect do begin
  1021.                     left := band(left + 1, $fffc);   {Word align}
  1022.                     right := band(right + 2, $fffc);
  1023.                     if right > PicRect.right then
  1024.                         right := PicRect.right;
  1025.                     MakeRegion;
  1026.                     wleft := left;
  1027.                     wtop := top;
  1028.                     width := right - left;
  1029.                     height := bottom - top;
  1030.                 end;
  1031.             end; {with info^}
  1032.         with frect do begin
  1033.                 left := wleft;
  1034.                 top := wtop;
  1035.                 right := left + width;
  1036.                 bottom := top + height;
  1037.             end;
  1038.         if UseExistingStack then begin
  1039.             if not Activate('Movie') then begin
  1040.                 PutError('Can''t find a stack named "Movie".');
  1041.                 UseExistingStack := false;
  1042.                 AbortMacro;
  1043.                 exit(MakeMovie);
  1044.             end;
  1045.             with info^ do begin
  1046.                 if (PixelsPerLine <> width) or (nLines <> height) then begin
  1047.                     PutError('The dimensions of the stack "Movie" are not the same as the selection.');
  1048.                     exit(MakeMovie);
  1049.                 end;
  1050.                 nFrames := StackInfo^.nSlices;
  1051.                 if nFrames > FramesWanted then
  1052.                     nFrames := FramesWanted;
  1053.             end {with info}
  1054.         end else begin
  1055.             if not NewPicWindow('Movie', width, height) then
  1056.                 exit(MakeMovie);
  1057.             if not MakeStackFromWindow then
  1058.                 exit(MakeMovie);
  1059.             nFrames := 1;
  1060.             OutOfMemory := false;
  1061.             while (nFrames < FramesWanted) and (not OutOfMemory) do begin
  1062.                     OutOfMemory := not AddSlice(false);
  1063.                     if not OutOfMemory then
  1064.                         nFrames := nFrames + 1;
  1065.                 end;
  1066.         end;
  1067.         if ExternalTrigger and not TriggerFirstFrameOnly then
  1068.             SecondsPerFrame := 0.0;
  1069.         If (FramesWanted < 1) then
  1070.             FramesWanted := 1;
  1071.         if SecondsPerFrame < 0.0 then
  1072.             SecondsPerFrame := 0.0;
  1073.         with info^.StackInfo^ do begin
  1074.             FrameInterval := 0.0;
  1075.             StackType := movieStack;
  1076.         end;
  1077.         if OptionKeyWasDown then
  1078.             CaptureFramesUsingTicks(SecondsPerFrame, nFrames, frect)
  1079.         else
  1080.             CaptureFramesUsingMicroTicks(SecondsPerFrame, nFrames, frect);
  1081.         ShowFirstOrLastSlice(HomeKey);
  1082.         avgFrameInterval := info^.StackInfo^.FrameInterval;
  1083.         if AvgFrameInterval <> 0.0 then
  1084.             ShowMessage(StringOf(nFrames:1, ' frames', cr,
  1085.                 AvgFrameInterval * nFrames:1:2, ' seconds', cr,
  1086.                 AvgFrameInterval:1:3, ' seconds/frame', cr,
  1087.                 1 / AvgFrameInterval:1:2, ' frames/second'));
  1088.         if TimeStamp then begin
  1089.             PlotData^[0] := nFrames;
  1090.             PlotData^[nFrames + 1] := SecondsPerFrame;
  1091.             PlotCount := 0;
  1092.         end;
  1093.     end;
  1094.  
  1095.  
  1096.     procedure CaptureFrames;
  1097.         var
  1098.             nFrames, wleft, wtop, width, height, i: integer;
  1099.             ignore, SaveFW: integer;
  1100.             OutOfMemory, AdvanceFrame, b: boolean;
  1101.             frect: rect;
  1102.             MainDevice: GDHandle;
  1103.             SourcePixMap: PixMapHandle;
  1104.             Event: EventRecord;
  1105.             ShutterSound: SndListHandle;
  1106.             err: OSErr;
  1107.  
  1108.         procedure CheckButton;
  1109.         begin
  1110.             if Button and not AdvanceFrame then
  1111.                 with Info^.StackInfo^ do begin
  1112.                         AdvanceFrame := true;
  1113.                         ShutterSound := SndListHandle(GetResource('snd ', 100));
  1114.                         if ShutterSound <> nil then
  1115.                             err := SndPlay(nil, ShutterSound, false);
  1116.                         if CurrentSlice < nSlices then begin
  1117.                                 CurrentSlice := CurrentSlice + 1;
  1118.                                 UpdateTitleBar;
  1119.                                 CurrentSlice := CurrentSlice - 1;
  1120.                             end;
  1121.                     end;
  1122.         end;
  1123.  
  1124.     begin
  1125.         with info^ do begin
  1126.                 if PictureType <> FrameGrabberType then begin
  1127.                         PutError('You must be capturing to capture frames.');
  1128.                         exit(CaptureFrames);
  1129.                     end;
  1130.                 StopDigitizing;
  1131.                 if not (RoiShowing and (RoiType = RectRoi)) then begin
  1132.                         PutError('Please make a rectangular selection first.');
  1133.                         exit(CaptureFrames);
  1134.                     end;
  1135.                 if NotInBounds then
  1136.                     exit(CaptureFrames);
  1137.                 SaveFW := FramesWanted;
  1138.                 ShutterSound := nil;
  1139.                 with RoiRect do begin
  1140.                         left := band(left + 1, $fffc);   {Word align}
  1141.                         right := band(right + 2, $fffc);
  1142.                         if right > PicRect.right then
  1143.                             right := PicRect.right;
  1144.                         MakeRegion;
  1145.                         wleft := left;
  1146.                         wtop := top;
  1147.                         width := right - left;
  1148.                         height := bottom - top;
  1149.                     end;
  1150.             end; {with info^}
  1151.         with frect do begin
  1152.                 left := wleft;
  1153.                 top := wtop;
  1154.                 right := left + width;
  1155.                 bottom := top + height;
  1156.             end;
  1157.         if not NewPicWindow('Frames', width, height) then
  1158.             exit(CaptureFrames);
  1159.         if not MakeStackFromWindow then
  1160.             exit(CaptureFrames);
  1161.         UpdateTitleBar;
  1162.         ShowWatch;
  1163.         SourcePixMap := fgPixMap;
  1164.         ResetFrameGrabber;
  1165.         FlushEvents(EveryEvent, 0);
  1166.         ExternalTrigger := false;
  1167.         UpdateVideoControl;
  1168.         with info^, info^.StackInfo^ do begin
  1169.                 ShowMessage(CmdPeriodToStop);
  1170.                 OutOfMemory := false;
  1171.                 AdvanceFrame := false;
  1172.                 while (not OutOfMemory) and (CurrentSlice <= MaxSlices) do begin
  1173.                         if AdvanceFrame then begin
  1174.                                 OutOfMemory := not AddSlice(false);
  1175.                                 AdvanceFrame := false;
  1176.                             end;
  1177.                         GetFrame;
  1178.                         CheckButton;
  1179.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  1180.                         CheckButton;
  1181.                         UpdatePicWindow;
  1182.                         CheckButton;
  1183.                         b := WaitNextEvent(EveryEvent, Event, 0, nil);
  1184.                         if event.what = KeyDown then
  1185.                             leave;
  1186.                     end; {while}
  1187.             end; {with}
  1188.         if ShutterSound <> nil then
  1189.             ReleaseResource(handle(ShutterSound));
  1190.     end;
  1191.  
  1192.  
  1193.  
  1194.     procedure CopyPics (sPort, dPort: cGrafPtr; sRect, dRect: rect);
  1195.     begin
  1196.         pmForeColor(BlackIndex);
  1197.         pmBackColor(WhiteIndex);
  1198.         CopyBits(BitMapHandle(sPort^.portPixMap)^^, BitMapHandle(dPort^.PortPixMap)^^, sRect, dRect, SrcCopy, nil);
  1199.         pmForeColor(ForegroundIndex);
  1200.         pmBackColor(BackgroundIndex);
  1201.     end;
  1202.  
  1203.  
  1204.     procedure MakeMontage;
  1205.   {Opens a new window and creates a composite image}
  1206.   {from the slices in the current stack.}
  1207.     const
  1208.         ColumnsID = 3;
  1209.         RowsID = 4;
  1210.         ScaleID = 5;
  1211.         FirstID = 6;
  1212.         LastID = 7;
  1213.         IncrementID = 8;
  1214.         NumberID = 9;
  1215.         BordersID=16;
  1216.     var
  1217.         mylog: DialogPtr;
  1218.         item, i, nRows, nColumns, Inc, slices: integer;
  1219.         StackWidth, StackHeight, mWidth, mHeight, Background: integer;
  1220.         dWidth, dHeight, dLeft, dTop, dRight, dBottom, MaxWidth, MaxHeight: integer;
  1221.         FirstSlice, LastSlice, TotalSlices: integer;
  1222.         scale, SaveScale: extended;
  1223.         sPort, dPort: cGrafPtr;
  1224.         StackInfo, MontageInfo: InfoPtr;
  1225.         sRect, dRect: rect;
  1226.         IncrementSet: boolean;
  1227.         str: str255;
  1228.         loc: point;
  1229.         SaveGDevice: GDHandle;
  1230.         
  1231.     procedure Estimate (var scale:extended{ppc-bug}; adjustinc: boolean);
  1232.         var
  1233.             tmp, xxScale, yyScale: extended;
  1234.             n: integer;
  1235.     begin
  1236.         slices := LastSlice - FirstSlice + 1;
  1237.         if adjustinc then
  1238.             inc := 0;
  1239.         repeat
  1240.             if adjustinc then
  1241.                 inc := inc + 1;
  1242.             n := trunc(slices / inc);
  1243.             tmp := sqrt(n);
  1244.             if trunc(tmp) <> tmp then
  1245.                 tmp := trunc(tmp) + 1.0;
  1246.             nColumns := trunc(tmp);
  1247.             nRows := nColumns;
  1248.             if (nColumns * (nRows - 1)) >= n then
  1249.                 nRows := nRows - 1;
  1250.             xxScale := (MaxWidth / nColumns) / StackWidth;
  1251.             yyScale := (MaxHeight / nRows) / StackHeight;
  1252.             if xxScale < yyScale then
  1253.                 scale := xxScale
  1254.             else
  1255.                 scale := yyScale;
  1256.             if scale > 1.0 then
  1257.                 scale := 1.0;
  1258.             SaveScale := scale;
  1259.         until (scale >= 0.5) or (inc >= 3) or not adjustinc;
  1260.     end;
  1261.  
  1262.     begin
  1263.         InitCursor;
  1264.         with info^ do begin
  1265.                 StackWidth := PixelsPerLine;
  1266.                 StackHeight := nLines;
  1267.                 FirstSlice := 1;
  1268.                 TotalSlices := StackInfo^.nSlices;
  1269.                 LastSlice := TotalSlices;
  1270.             end;
  1271.         MaxWidth := ScreenWidth - 85;
  1272.         MaxHeight := ScreenHeight - 45;
  1273.         Estimate(scale, true);
  1274.         IncrementSet := false;
  1275.         mylog := GetNewDialog(150, nil, pointer(-1));
  1276.         SetDNum(MyLog, RowsID, nRows);
  1277.         SetDNum(MyLog, ColumnsID, nColumns);
  1278.         SetDReal(MyLog, ScaleID, scale, 2);
  1279.         SetDNum(MyLog, FirstID, FirstSlice);
  1280.         SetDNum(MyLog, LastID, LastSlice);
  1281.         SetDNum(MyLog, IncrementID, inc);
  1282.         SetDlogItem(MyLog, NumberID, ord(gNumberSlices));
  1283.         SetDlogItem(MyLog, BordersID, ord(gBorders));
  1284.         OutlineButton(MyLog, ok, 16);
  1285.         repeat
  1286.             ModalDialog(nil, item);
  1287.             if item = ColumnsID then begin
  1288.                     nColumns := GetDNum(MyLog, ColumnsID);
  1289.                     if nColumns < 0 then begin
  1290.                             nColumns := 0;
  1291.                             SetDNum(MyLog, ColumnsID, nRows);
  1292.                         end;
  1293.                 end;
  1294.             if item = RowsID then begin
  1295.                     nRows := GetDNum(MyLog, RowsID);
  1296.                     if nRows < 0 then begin
  1297.                             nRows := 0;
  1298.                             SetDNum(MyLog, RowsID, nRows);
  1299.                         end;
  1300.                 end;
  1301.             if item = ScaleID then
  1302.                 scale := GetDReal(MyLog, ScaleID);
  1303.             if item = FirstID then begin
  1304.                     FirstSlice := GetDNum(MyLog, FirstID);
  1305.                     if (FirstSlice < 1) or (FirstSlice > LastSlice) then
  1306.                         FirstSlice := 1;
  1307.                     if IncrementSet then
  1308.                         Estimate(scale, false)
  1309.                     else
  1310.                         Estimate(scale, true);
  1311.                     SetDNum(MyLog, RowsID, nRows);
  1312.                     SetDNum(MyLog, ColumnsID, nColumns);
  1313.                     SetDReal(MyLog, ScaleID, scale, 2);
  1314.                 end;
  1315.             if item = LastID then begin
  1316.                     LastSlice := GetDNum(MyLog, LastID);
  1317.                     if (LastSlice < FirstSlice) or (LastSlice > TotalSlices) then
  1318.                         LastSlice := TotalSlices;
  1319.                     if IncrementSet then
  1320.                         Estimate(scale, false)
  1321.                     else
  1322.                         Estimate(scale, true);
  1323.                     SetDNum(MyLog, RowsID, nRows);
  1324.                     SetDNum(MyLog, ColumnsID, nColumns);
  1325.                     SetDReal(MyLog, ScaleID, scale, 2);
  1326.                 end;
  1327.             if item = IncrementID then begin
  1328.                     inc := GetDNum(MyLog, IncrementID);
  1329.                     IncrementSet := true;
  1330.                     if (inc < 1) or (inc > (slices div 2)) then begin
  1331.                             inc := 1;
  1332.                             SetDNum(MyLog, IncrementID, inc);
  1333.                         end;
  1334.                     Estimate(scale, false);
  1335.                     SetDNum(MyLog, RowsID, nRows);
  1336.                     SetDNum(MyLog, ColumnsID, nColumns);
  1337.                     SetDReal(MyLog, ScaleID, scale, 2);
  1338.                 end;
  1339.             if item = NumberID then begin
  1340.                     gNumberSlices := not gNumberSlices;
  1341.                     SetDlogItem(MyLog, NumberID, ord(gNumberSlices));
  1342.                 end;
  1343.             if item = BordersID then begin
  1344.                     gBorders := not gBorders;
  1345.                     SetDlogItem(MyLog, BordersID, ord(gBorders));
  1346.                 end;
  1347.         until (item = ok) or (item = cancel);
  1348.         DisposeDialog(mylog);
  1349.         if item = cancel then
  1350.             exit(MakeMontage);
  1351.         if (scale <= 0.05) or (scale > 5) then
  1352.             scale := SaveScale;
  1353.         dWidth := round(StackWidth * scale);
  1354.         dHeight := round(StackHeight * scale);
  1355.         mWidth := nColumns * dWidth;
  1356.         mHeight := nRows * dHeight;
  1357.         StackInfo := info;
  1358.         Background := MyGetPixel(0, 0);
  1359.         SetBackgroundColor(Background);
  1360.         if Background = WhiteIndex then
  1361.             SetForegroundColor(BlackIndex)
  1362.         else
  1363.             SetForegroundColor(WhiteIndex);
  1364.         if not NewPicWindow('Montage', mWidth, mHeight) then
  1365.             exit(MakeMontage);
  1366.         MontageInfo := info;
  1367.         SaveGDevice := GetGDevice;
  1368.         SetGDevice(osGDevice);
  1369.         SetPort(GrafPtr(info^.osPort));
  1370.         pmForeColor(ForegroundIndex);
  1371.         dPort := info^.osPort;
  1372.         dLeft := 0;
  1373.         dTop := 0;
  1374.         sPort := StackInfo^.osPort;
  1375.         sRect := StackInfo^.PicRect;
  1376.         i := FirstSlice;
  1377.         while i <= LastSlice do begin
  1378.                 Info := StackInfo;
  1379.                 SelectSlice(i);
  1380.                 SetRect(dRect, dLeft, dTop, dLeft + dWidth, dTop + DHeight);
  1381.                 CopyPics(sPort, dPort, sRect, dRect);
  1382.                 info := MontageInfo;
  1383.                 if gNumberSlices then begin
  1384.                         MoveTo(dLeft + (dWidth div 2) - 3, dTop + dHeight - 9);
  1385.                         NumToString(i, str);
  1386.                         loc.h := dLeft + (dWidth div 2) - 3;
  1387.                         loc.v := dTop + dHeight - 5;
  1388.                         DrawTextString(str, loc, TeJustCenter);
  1389.                     end;
  1390.                 if gBorders then with dRect do begin
  1391.                     PenSize(LineWidth, LineWidth);
  1392.                     MoveTo(left,bottom);
  1393.                     LineTo(left,top);
  1394.                     LineTo(right,top);
  1395.                     LineTo(right,bottom);
  1396.                     LineTo(left,bottom);
  1397.                 end;
  1398.                 UpdateScreen(dRect);
  1399.                 dLeft := dLeft + dWidth;
  1400.                 if (dLeft + dWidth) > mWidth then begin
  1401.                         dLeft := 0;
  1402.                         dTop := dTop + dHeight;
  1403.                     end;
  1404.                 i := i + inc;
  1405.             end;
  1406.         if gBorders then
  1407.             FrameRect(info^.PicRect);
  1408.         SetGDevice(SaveGDevice);
  1409.         info := StackInfo;
  1410.         SelectSlice(info^.StackInfo^.CurrentSlice);
  1411.         info := MontageInfo;
  1412.         if info^.PixMapSize > UndoBufSize then
  1413.             PutWarning;
  1414.     end;
  1415.  
  1416.  
  1417.     procedure CopyRGBToPixMap (pmap: PixMapHandle);
  1418.         type
  1419.             LongPtr = ^LongInt;
  1420.         var
  1421.             row, i, width, WatchRate: integer;
  1422.             RedLine, GreenLine, BlueLine: LineType;
  1423.             Pixel, RowOffset: LongInt;
  1424.             pmapPtr: ptr;
  1425.             LPtr, RowStart: LongPtr;
  1426.     begin
  1427.         with info^ do begin
  1428.                 pmapPtr := GetPixBaseAddr(pmap);
  1429.                 if pmapPtr = nil then
  1430.                     exit(CopyRGBToPixMap);
  1431.                 LPtr := LongPtr(pmapPtr);
  1432.                 RowStart := LPtr;
  1433.                 RowOffset := band(pmap^^.RowBytes, $3FFF);
  1434.                 width := PicRect.right;
  1435.                 WatchRate := 40000 div PixelsPerLine;
  1436.                 for row := 0 to nLines - 1 do begin
  1437.                         if (row mod WatchRate) = 0 then
  1438.                             ShowAnimatedWatch;
  1439.                         SelectSlice(1);
  1440.                         GetLine(0, row, width, RedLine);
  1441.                         SelectSlice(2);
  1442.                         GetLine(0, row, width, GreenLine);
  1443.                         SelectSlice(3);
  1444.                         GetLine(0, row, width, BlueLine);
  1445.                         LPtr := RowStart;
  1446.                         for i := 0 to PixelsPerLine - 1 do begin
  1447.                                 pixel := -1;
  1448.                                 pixel := RedLine[i];
  1449.                                 pixel := bor(bsl(pixel, 8), GreenLine[i]);
  1450.                                 pixel := bor(bsl(pixel, 8), blueLine[i]);
  1451.                                 LPtr^ := BitNot(pixel);
  1452.                                 LPtr := LongPtr(ord4(LPtr) + 4);
  1453.                             end;
  1454.                         RowStart := LongPtr(ord4(RowStart) + RowOffset);
  1455.                     end;
  1456.                 SelectSlice(StackInfo^.CurrentSlice);
  1457.             end; {with}
  1458.     end;
  1459.  
  1460.  
  1461.     function DoColorOptions: boolean;
  1462.         const
  1463.             ExistingID = 4;
  1464.             SystemID = 5;
  1465.             CustomID = 6;
  1466.             DitherID = 7;
  1467.         var
  1468.             mylog: DialogPtr;
  1469.             item: integer;
  1470.  
  1471.         procedure UpdateButtons;
  1472.         begin
  1473.             SetDlogItem(mylog, ExistingID, ord(RGBLut = ExistingLUT));
  1474.             SetDlogItem(mylog, SystemID, ord(RGBLut = SystemLUT));
  1475.             SetDlogItem(mylog, CustomID, ord(RGBLut = CustomLUT));
  1476.         end;
  1477.  
  1478.     begin
  1479.         InitCursor;
  1480.         mylog := GetNewDialog(160, nil, pointer(-1));
  1481.         SetDlogItem(mylog, DitherID, ord(DitherColor));
  1482.         UpdateButtons;
  1483.         OutlineButton(MyLog, ok, 16);
  1484.         repeat
  1485.             ModalDialog(nil, item);
  1486.             if item = DitherID then begin
  1487.                     DitherColor := not DitherColor;
  1488.                     SetDlogItem(mylog, DitherID, ord(DitherColor));
  1489.                 end;
  1490.             if item = ExistingID then begin
  1491.                     RGBLut := ExistingLUT;
  1492.                     UpdateButtons
  1493.                 end;
  1494.             if item = SystemID then begin
  1495.                     RGBLut := SystemLUT;
  1496.                     UpdateButtons;
  1497.                     DitherColor := true;
  1498.                     SetDlogItem(mylog, DitherID, ord(DitherColor));
  1499.                 end;
  1500.             if item = CustomID then begin
  1501.                     RGBLut := CustomLUT;
  1502.                     UpdateButtons
  1503.                 end;
  1504.         until (item = ok) or (item = cancel);
  1505.         DisposeDialog(mylog);
  1506.         DoColorOptions := item <> cancel;
  1507.     end;
  1508.  
  1509.  
  1510.  
  1511.     procedure ConvertRGBToEightBitColor (Capturing: boolean);
  1512.         var
  1513.             err: QDErr;
  1514.             err2: OSErr;
  1515.             osGWorld: GWorldPtr;
  1516.             flags: GWorldFlags;
  1517.             pmap: PixMapHandle;
  1518.             pRect: rect;
  1519.             thePictInfo: PictInfo;
  1520.             CopyMode, SamplingMethod: integer;
  1521.             UpdateNeeded: boolean;
  1522.             SaveGDevice: GDHandle;
  1523.     begin
  1524.         if not System7 then begin
  1525.                 PutError('You must be running System 7 to do 24 to 8-bit color conversions.');
  1526.                 exit(ConvertRGBToEightBitColor);
  1527.             end;
  1528.         with info^ do begin
  1529.                 if StackInfo^.nSlices <> 3 then begin
  1530.                         PutError('24 to 8-bit color conversion requires a three slice (red, green and blue) stack as input.');
  1531.                         exit(ConvertRGBToEightBitColor);
  1532.                     end;
  1533.                 if StackInfo^.StackType <> rgbStack then begin;
  1534.                     StackInfo^.StackType := rgbStack;
  1535.                     UpdateTitleBar;
  1536.                 end;
  1537.                 if Capturing then begin
  1538.                         DitherColor := true;
  1539.                         RGBLut := CustomLUT;
  1540.                     end
  1541.                 else if not macro then begin
  1542.                         if not DoColorOptions then
  1543.                             exit(ConvertRGBToEightBitColor);
  1544.                     end;
  1545.                 flags := 0; {ppc-bug}
  1546.                 SaveGDevice := GetGDevice;
  1547.                 SetGDevice(osGDevice);
  1548.                 err := NewGWorld(osGWorld, 32, PicRect, nil, nil, flags);
  1549.                 SetGDevice(SaveGDevice);
  1550.                 if err <> NoErr then begin
  1551.                         PutMemoryAlert;
  1552.                         exit(ConvertRGBToEightBitColor);
  1553.                     end;
  1554.                 pmap := GetGWorldPixMap(osGWorld);
  1555.                 if not LockPixels(pmap) then
  1556.                     begin
  1557.                         DisposeGWorld(osGWorld);
  1558.                         exit(ConvertRGBToEightBitColor);
  1559.                     end;
  1560.                 CopyRGBToPixMap(pmap);
  1561.                 pRect := PicRect;
  1562.             end; {with}
  1563.         UpdateNeeded := true;
  1564.         if Activate('Indexed Color') then begin
  1565.                 if (info^.PixelsPerLine <> pRect.right) or (info^.nLines <> pRect.bottom) then begin
  1566.                         if not NewPicWindow('Indexed Color', pRect.right, pRect.bottom) then
  1567.                             begin
  1568.                                 DisposeGWorld(osGWorld);
  1569.                                 exit(ConvertRGBToEightBitColor);
  1570.                             end;
  1571.                         UpdateNeeded := false;
  1572.                     end
  1573.             end
  1574.         else begin
  1575.                 if not NewPicWindow('Indexed Color', pRect.right, pRect.bottom) then
  1576.                     begin
  1577.                         DisposeGWorld(osGWorld);
  1578.                         exit(ConvertRGBToEightBitColor);
  1579.                     end;
  1580.                 UpdateNeeded := false;
  1581.             end;
  1582.         if RGBLut = SystemLUT then
  1583.             SwitchColorTables(SystemPaletteItem, false)
  1584.         else if RGBLut = CustomLut then begin
  1585.                 if OptionKeyWasDown then
  1586.                     SamplingMethod := PopularMethod
  1587.                 else
  1588.                     SamplingMethod := SystemMethod;
  1589.                 err2 := GetPixMapInfo(pmap, thePictInfo, ReturnColorTable, 256, SamplingMethod, 0);
  1590.                 LoadColorTable(thePictInfo.theColorTable);
  1591.             end;
  1592.         SetForegroundColor(BlackIndex);
  1593.         SetBackgroundColor(WhiteIndex);
  1594.         if DitherColor then
  1595.             CopyMode := DitherCopy
  1596.         else
  1597.             CopyMode := SrcCopy;
  1598.         SetGDevice(osGDevice);
  1599.         SetPort(GrafPtr(Info^.osPort));
  1600.         CopyBits(BitMapHandle(pmap)^^, BitMapHandle(info^.osPort^.PortPixMap)^^, pRect, pRect, CopyMode, nil);
  1601.         DisposeGWorld(osGWorld);
  1602.         SetGDevice(SaveGDevice);
  1603.         if UpdateNeeded then
  1604.             UpdatePicWindow;
  1605.     end;
  1606.  
  1607.  
  1608.     function MakeRGBStack (name: str255): boolean;
  1609.         var
  1610.             ignore: integer;
  1611.     begin
  1612.         MakeRGBStack := false;
  1613.         if not Duplicate(name, false) then
  1614.             exit(MakeRGBStack);
  1615.         if not MakeStackFromWindow then
  1616.             exit(MakeRGBStack);
  1617.         if not AddSlice(false) then begin
  1618.                 info^.changes := false;
  1619.                 ignore := CloseAWindow(info^.wptr);
  1620.                 exit(MakeRGBStack);
  1621.             end;
  1622.         if not AddSlice(false) then begin
  1623.                 info^.changes := false;
  1624.                 ignore := CloseAWindow(info^.wptr);
  1625.                 exit(MakeRGBStack);
  1626.             end;
  1627.         MakeRGBStack := true;
  1628.     end;
  1629.  
  1630.  
  1631.     procedure ConvertEightBitColorToRGB;
  1632.         var
  1633.             width, height, i, row: integer;
  1634.             srcLine, rLine, gLine, bLine: LineType;
  1635.             rLut, gLUT, bLUT: packed array[0..255] of byte;
  1636.             value: byte;
  1637.     begin
  1638.         if isGrayscaleLUT then begin
  1639.                 PutError('8-bit color to RGB conversion requires a color image.');
  1640.                 exit(ConvertEightBitColorToRGB);
  1641.             end;
  1642.         KillRoi;
  1643.         if not MakeRGBStack(concat(info^.title, ' (RGB)')) then
  1644.             exit(ConvertEightBitColorToRGB);
  1645.         LoadLUT(Info^.cTable);
  1646.         if ScreenDepth = 8 then begin
  1647.             for i := 0 to 255 do
  1648.                 with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  1649.                         rLUT[i] := BitNot(band(bsr(red, 8), 255));
  1650.                         gLUT[i] := BitNot(band(bsr(green, 8), 255));
  1651.                         bLUT[i] := BitNot(band(bsr(blue, 8), 255));
  1652.                     end;
  1653.         end else begin
  1654.             for i := 0 to 255 do
  1655.                 with info^.cTable[i].rgb do begin
  1656.                         rLUT[i] := BitNot(band(bsr(red, 8), 255));
  1657.                         gLUT[i] := BitNot(band(bsr(green, 8), 255));
  1658.                         bLUT[i] := BitNot(band(bsr(blue, 8), 255));
  1659.                     end;
  1660.         end;
  1661.         width := info^.PixelsPerLine;
  1662.         height := info^.nLines;
  1663.         for row := 0 to height - 1 do begin
  1664.                 SelectSlice(1);
  1665.                 GetLine(0, row, width, srcLine);
  1666.                 for i := 0 to width - 1 do begin
  1667.                         value := srcLine[i];
  1668.                         rLine[i] := rLUT[value];
  1669.                         gLine[i] := gLUT[value];
  1670.                         bLine[i] := bLUT[value];
  1671.                     end;
  1672.                 PutLine(0, row, width, rLine);
  1673.                 SelectSlice(2);
  1674.                 PutLine(0, row, width, gLine);
  1675.                 SelectSlice(3);
  1676.                 PutLine(0, row, width, bLine);
  1677.             end;
  1678.         with Info^.StackInfo^ do begin
  1679.                 CurrentSlice := 1;
  1680.                 SelectSlice(CurrentSlice);
  1681.                 StackType := rgbStack;
  1682.                 UpdateTitleBar;
  1683.             end;
  1684.         ResetGrayMap;
  1685.     end;
  1686.  
  1687.  
  1688.     procedure CopyGWorldToStack;
  1689.     {Copies the color image stored in the 32-bit GWorld used by QuickTime
  1690.      video digitizers to a 3 slice (RGB) stack.}
  1691.         type
  1692.             LongPtr = ^LongInt;
  1693.         var
  1694.             row, i, width, WatchRate: integer;
  1695.             RedLine, GreenLine, BlueLine: LineType;
  1696.             Pixel, RowOffset: LongInt;
  1697.             pmapPtr: ptr;
  1698.             LPtr, RowStart: LongPtr;
  1699.     begin
  1700.         if fgPixMap^^.pixelSize <> 32 then begin
  1701.             PutError('RGB capture requires a 24-bit digitizer.');
  1702.             DigitizerMode := digitizeColor;
  1703.             exit(CopyGWorldToStack);
  1704.         end;
  1705.         if not MakeRGBStack(StringOf('RGB-', nPics:1)) then
  1706.             exit(CopyGWorldToStack);
  1707.         with info^ do begin
  1708.             pmapPtr := GetPixBaseAddr(fgPixMap);
  1709.             if pmapPtr = nil then
  1710.                 exit(CopyGWorldToStack);
  1711.             LPtr := LongPtr(pmapPtr);
  1712.             RowStart := LPtr;
  1713.             RowOffset := band(fgPixMap^^.RowBytes, $3FFF);
  1714.             width := PicRect.right;
  1715.             WatchRate := 40000 div PixelsPerLine;
  1716.             for row := 0 to nLines - 1 do begin
  1717.                     if (row mod WatchRate) = 0 then
  1718.                         ShowAnimatedWatch;
  1719.                     LPtr := RowStart;
  1720.                     for i := 0 to PixelsPerLine - 1 do begin
  1721.                             pixel := BitNot(LPtr^);
  1722.                             blueLine[i] := band(pixel, 255);
  1723.                             pixel := bsr(pixel, 8);
  1724.                             greenLine[i] := band(pixel, 255);
  1725.                             pixel := bsr(pixel, 8);
  1726.                             redLine[i] := band(pixel, 255);
  1727.                             LPtr := LongPtr(ord4(LPtr) + 4);
  1728.                         end;
  1729.                     RowStart := LongPtr(ord4(RowStart) + RowOffset);
  1730.                     SelectSlice(1);
  1731.                     PutLine(0, row, width, RedLine);
  1732.                     SelectSlice(2);
  1733.                     PutLine(0, row, width, GreenLine);
  1734.                     SelectSlice(3);
  1735.                     PutLine(0, row, width, BlueLine);
  1736.                 end;
  1737.             with Info^.StackInfo^ do begin
  1738.                     CurrentSlice := 1;
  1739.                     SelectSlice(CurrentSlice);
  1740.                     StackType := rgbStack;
  1741.                     UpdateTitleBar;
  1742.                 end;
  1743.             ResetGrayMap;
  1744.         end; {with}
  1745.     end;
  1746.  
  1747.  
  1748.     procedure CaptureVDigColor;
  1749.         var
  1750.             err: OSErr;
  1751.             pRect: rect;
  1752.             thePictInfo: PictInfo;
  1753.             SaveGDevice: GDHandle;
  1754.     begin
  1755.         if DigitizerMode = digitizeGrayscale then begin
  1756.             PutError('To capture color, "8-bit Color" or "RGB Color" must be selected in Video Control.');
  1757.             exit(CaptureVDigColor);
  1758.         end;
  1759.         if not digitizing then begin
  1760.             if info^.PictureType <> FrameGrabberType then
  1761.                 SelectCameraWindow;
  1762.             CaptureAndDisplayFrame;
  1763.         end;
  1764.         if fgPixMap = nil then
  1765.             exit(CaptureVDigColor);
  1766.         SaveGDevice := GetGDevice;
  1767.         err := GetPixMapInfo(fgPixMap, thePictInfo, ReturnColorTable, 256, SystemMethod, 0);
  1768.         if err = noErr then begin
  1769.             LoadColorTable(thePictInfo.theColorTable);
  1770.             SetForegroundColor(BlackIndex);
  1771.             SetBackgroundColor(WhiteIndex);
  1772.             SetGDevice(osGDevice);
  1773.             SetPort(GrafPtr(Info^.osPort));
  1774.             with info^ do
  1775.                 CopyBits(BitMapHandle(fgPixMap)^^, BitMapHandle(osPort^.PortPixMap)^^, picRect, picRect, DitherCopy, nil);
  1776.             SetGDevice(SaveGDevice);
  1777.             UpdatePicWindow;
  1778.             DrawLUT;
  1779.         end;
  1780.         if DigitizerMode = digitizeRGB then
  1781.             CopyGWorldToStack;
  1782.     end;
  1783.  
  1784.  
  1785.     procedure CaptureColor;
  1786.         var
  1787.             MainDevice: GDHandle;
  1788.             SourcePixMap: PixMapHandle;
  1789.             frame, width, height, SaveChannel: integer;
  1790.             frect: rect;
  1791.     begin
  1792.         with info^ do
  1793.             if PictureType <> FrameGrabberType then begin
  1794.                     PutError('You must be capturing to capture color.');
  1795.                     AbortMacro;
  1796.                     exit(CaptureColor);
  1797.                 end;
  1798.         StopDigitizing;
  1799.         if frameGrabber = QTvdig then begin
  1800.             CaptureVDigColor;
  1801.             exit(CaptureColor);
  1802.         end;
  1803.         with info^.PicRect do begin
  1804.                 width := right - left;
  1805.                 height := bottom - top;
  1806.             end;
  1807.         if Activate('RGB') then
  1808.             with info^.PicRect do begin
  1809.                     if ((right - left) <> width) or ((bottom - top) <> height) then
  1810.                         if not MakeRGBStack('RGB') then
  1811.                             exit(CaptureColor);
  1812.                 end
  1813.         else if not MakeRGBStack('RGB') then
  1814.             exit(CaptureColor);
  1815.         ShowWatch;
  1816.         SourcePixMap := fgPixMap;
  1817.         ResetFrameGrabber;
  1818.         with frect do begin
  1819.                 left := 0;
  1820.                 top := 0;
  1821.                 right := left + width;
  1822.                 bottom := top + height;
  1823.             end;
  1824.         ShowTriggerMessage;
  1825.         SaveChannel := VideoChannel;
  1826.         with info^, info^.StackInfo^ do begin
  1827.                 for frame := 1 to 3 do begin
  1828.                         if FrameGrabber = QuickCapture then begin
  1829.                                 case frame of
  1830.                                     1: 
  1831.                                         VideoChannel := 1; {Green}
  1832.                                     2: 
  1833.                                         VideoChannel := 0;  {Red}
  1834.                                     3: 
  1835.                                         VideoChannel := 2;  {Blue}
  1836.                                 end;
  1837.                                 ResetFrameGrabber;
  1838.                                 repeat
  1839.                                 until band(ControlReg^, $8) = 0; {mux channel not busy}
  1840.                             end
  1841.                         else begin
  1842.                                 VideoChannel := frame - 1;
  1843.                                 ResetFrameGrabber;
  1844.                             end;
  1845.                         if VideoControl <> nil then
  1846.                             ShowChannel;
  1847.                         CurrentSlice := frame;
  1848.                         SelectSlice(CurrentSlice);
  1849.                         GetFrame;
  1850.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  1851.                     end; {for}
  1852.                 CurrentSlice := 1;
  1853.                 SelectSlice(CurrentSlice);
  1854.                 UpdateTitleBar;
  1855.             end; {with}
  1856.         VideoChannel := SaveChannel;
  1857.         if VideoControl <> nil then
  1858.             ShowChannel;
  1859.         ConvertRGBToEightBitColor(true);
  1860.     end;
  1861.  
  1862.  
  1863.     procedure AverageSlices(FirstSlice, SliceCount: integer);
  1864.         const
  1865.             MaxWidth = 2048;
  1866.         var
  1867.             sRow, aRow, slice, i, SaveSlice: integer;
  1868.             width, height, hstart, vStart: integer;
  1869.             OldInfo, NewInfo: InfoPtr;
  1870.             aLine: LineType;
  1871.             mask: rect;
  1872.             sum: array[0..MaxWidth] of LongInt;
  1873.             AutoSelectAll: boolean;
  1874.             SlicesDiv2:LongInt;
  1875.     begin
  1876.         OldInfo := Info;
  1877.         with info^ do begin
  1878.                 if StackInfo = nil then begin
  1879.                         PutError('Average Slices requires a stack.');
  1880.                         AbortMacro;
  1881.                         exit(AverageSlices);
  1882.                     end;
  1883.                 AutoSelectAll := not Info^.RoiShowing;
  1884.                 if AutoSelectAll then
  1885.                     SelectAll(true);
  1886.                 with RoiRect do begin
  1887.                         hStart := left;
  1888.                         vStart := top;
  1889.                         width := right - left;
  1890.                         height := bottom - top;
  1891.                     end;
  1892.                 if width > MaxWidth then begin
  1893.                         PutError(concat('NIH Image can''t average selections wider than ', Long2str(MaxWidth), ' pixels.'));
  1894.                         AbortMacro;
  1895.                         exit(AverageSlices);
  1896.                     end;
  1897.                 if (FirstSlice < 1) or ((FirstSlice + SliceCount - 1) > StackInfo^.nSlices) then begin
  1898.                     FirstSlice := 1;
  1899.                     SliceCount := StackInfo^.nSlices;
  1900.                 end;
  1901.                 SaveSlice := StackInfo^.CurrentSlice;
  1902.                 if not NewPicWindow('Average', width, height) then begin
  1903.                         AbortMacro;
  1904.                         exit(AverageSlices);
  1905.                     end;
  1906.             end;
  1907.         info^.changes := true;
  1908.         NewInfo := Info;
  1909.         aRow := 0;
  1910.         SlicesDiv2:=SliceCount div 2; {Needed for rounding}
  1911.         for sRow := vStart to vStart + height - 1 do begin
  1912.                 info := OldInfo;
  1913.                 for i := 0 to width - 1 do
  1914.                     sum[i] := 0;
  1915.                 for slice := FirstSlice to FirstSlice + SliceCount - 1 do begin
  1916.                         SelectSlice(slice);
  1917.                         GetLine(hStart, sRow, width, aLine);
  1918.                         for i := 0 to width - 1 do
  1919.                             sum[i] := sum[i] + aLine[i];
  1920.                     end;
  1921.                 for i := 0 to width - 1 do
  1922.                     aLine[i] := (sum[i]+SlicesDiv2) div SliceCount;
  1923.                 info := NewInfo;
  1924.                 PutLine(0, aRow, width, aLine);
  1925.                 SetRect(mask, 0, aRow, width, aRow + 1);
  1926.                 aRow := aRow + 1;
  1927.                 UpdateScreen(mask);
  1928.                 if CommandPeriod then
  1929.                     leave;
  1930.             end;
  1931.         info := OldInfo;
  1932.         SelectSlice(SaveSlice);
  1933.         if AutoSelectAll then
  1934.             KillRoi;
  1935.         info:=NewInfo;
  1936.     end;
  1937.  
  1938.  
  1939.     procedure ConvertRGBToHSV;
  1940.         const
  1941.             MaxSaturation = 255;
  1942.             MaxValue = 255;
  1943.         var
  1944.             width, height, i, row, mark: integer;
  1945.             rLine, gLine, bLine, hLine, sLine, vLine: LineType;
  1946.             delta, min, max, R, G, B, H, S, V: integer;
  1947.             tmp: longint;
  1948.             UpdateR: rect;
  1949.  
  1950.         function Max3 (a, b, c: integer): integer;
  1951.             var
  1952.                 TempMax: integer;
  1953.         begin
  1954.             if (a > b) then
  1955.                 TempMax := a
  1956.             else
  1957.                 TempMax := b;
  1958.             if (TempMax > c) then
  1959.                 Max3 := TempMax
  1960.             else
  1961.                 Max3 := c;
  1962.         end;
  1963.  
  1964.         function Min3 (a, b, c: integer): integer;
  1965.             var
  1966.                 TempMin: integer;
  1967.         begin
  1968.             if (a < b) then
  1969.                 TempMin := a
  1970.             else
  1971.                 TempMin := b;
  1972.             if (TempMin < c) then
  1973.                 Min3 := TempMin
  1974.             else
  1975.                 Min3 := c;
  1976.         end;
  1977.  
  1978.     begin
  1979.         with info^ do begin
  1980.                 if StackInfo^.nSlices <> 3 then begin
  1981.                         PutError('RGB to HSV color conversion requires a three slice(red, green and blue) stack as input.');
  1982.                         exit(ConvertRGBToHSV);
  1983.                     end;
  1984.                 if Changes then begin
  1985.                         if PutMessageWithCancel('RGB to HSV color conversion is undoable.') = cancel then
  1986.                             exit(ConvertRGBToHSV);
  1987.                     end;
  1988.                 KillRoi;
  1989.                 with StackInfo^ do begin
  1990.                         CurrentSlice := 1;
  1991.                         SelectSlice(CurrentSlice);
  1992.                         UpdatePicWindow;
  1993.                     end;
  1994.                 SwitchColorTables(SpectrumItem, true);
  1995.                 title := 'HSV';
  1996.                 UpdateTitleBar;
  1997.                 width := PixelsPerLine;
  1998.                 height := nLines;
  1999.                 mark := 0;
  2000.                 ShowWatch;
  2001.                 for row := 0 to height - 1 do begin
  2002.                         SelectSlice(1);
  2003.                         GetLine(0, row, width, rLine);
  2004.                         SelectSlice(2);
  2005.                         GetLine(0, row, width, gLine);
  2006.                         SelectSlice(3);
  2007.                         GetLine(0, row, width, bLine);
  2008.                         for i := 0 to width - 1 do begin
  2009.                                 R := 255 - rLine[i];
  2010.                                 G := 255 - gLine[i];
  2011.                                 B := 255 - bLine[i];
  2012.                                 max := Max3(R, G, B);
  2013.                                 min := Min3(R, G, B);
  2014.                                 V := max;
  2015.                                 if max <> 0 then begin
  2016.                                         tmp := 255 * (max - min);
  2017.                                         S := (tmp + (tmp mod max)) div max;  {adding '(tmp mod max)' simulate rounding}
  2018.                                     end
  2019.                                 else
  2020.                                     S := 0;
  2021.                                 if S = 0 then
  2022.                                     H := 0  {undefined but, but select red }
  2023.                                 else begin
  2024.                                         delta := max - min;
  2025.                                         if R = max then begin
  2026.                                                 tmp := 85 * (G - B);
  2027.                                                 H := tmp div delta;
  2028.                                             end
  2029.                                         else if G = max then begin
  2030.                                                 tmp := 85 * (B - R);
  2031.                                                 H := 170 + tmp div delta;
  2032.                                             end
  2033.                                         else if B = max then begin
  2034.                                                 tmp := 85 * (R - G);
  2035.                                                 H := 340 + tmp div delta;
  2036.                                             end;
  2037.                                         H := H div 2;
  2038.                                         if H < 0 then
  2039.                                             H := H + 255
  2040.                                     end;
  2041.                                 if H = 0 then
  2042.                                     hLine[i] := 1
  2043.                                 else
  2044.                                     hLine[i] := H;
  2045.                                 sLine[i] := S;
  2046.                                 vLine[i] := 255 - V;
  2047.                             end;
  2048.                         SelectSlice(1);
  2049.                         PutLine(0, row, width, hLine);
  2050.                         if (row mod 10) = 0 then begin
  2051.                                 setrect(UpdateR, 0, mark, width - 1, row);
  2052.                                 mark := row;
  2053.                                 UpdateScreen(UpdateR);
  2054.                             end;
  2055.                         SelectSlice(2);
  2056.                         PutLine(0, row, width, sLine);
  2057.                         SelectSlice(3);
  2058.                         PutLine(0, row, width, vLine);
  2059.                     end;
  2060.                 SelectSlice(1);
  2061.                 StackInfo^.StackType := hsvStack;
  2062.                 UpdateTitleBar;
  2063.             end; {with}
  2064.         WhatToUndo := NothingToUndo;
  2065.     end;
  2066.  
  2067.  
  2068.     procedure DoStackInfo;
  2069.     const
  2070.         VolumeID = 5;
  2071.         MovieID = 6;
  2072.         RGBID = 7;
  2073.         HSVID = 8;
  2074.         SpacingID = 11;
  2075.         IntervalID = 12;
  2076.     var
  2077.         mylog: DialogPtr;
  2078.         item: integer;
  2079.         spacing, SaveSpacing, SaveInterval: extended;
  2080.         SaveType: StackTypeType;
  2081.         str: str255;
  2082.         
  2083.         procedure ShowStackType;
  2084.         begin
  2085.             With info^.StackInfo^ do begin
  2086.                 SetDlogItem(MyLog, VolumeID, ord(StackType = VolumeStack));
  2087.                 SetDlogItem(MyLog, MovieID, ord(StackType = MovieStack));
  2088.                 SetDlogItem(MyLog, RGBID, ord(StackType = rgbStack));
  2089.                 SetDlogItem(MyLog, HSVID, ord(StackType = hsvStack));
  2090.             end;
  2091.         end;
  2092.         
  2093.     begin
  2094.         With info^, info^.StackInfo^ do begin
  2095.             InitCursor;
  2096.             mylog := GetNewDialog(280, nil, pointer(-1));
  2097.             SaveType := StackType;
  2098.             SaveSpacing := SliceSpacing;
  2099.             SaveInterval := Frameinterval;
  2100.             ShowStackType;
  2101.             if SpatiallyCalibrated then begin
  2102.                 spacing := SliceSpacing / xScale;
  2103.                 str := xunit;
  2104.             end else begin
  2105.                 spacing := SliceSpacing;
  2106.                 str := 'pixels'
  2107.             end;
  2108.             SetDReal(MyLog, SpacingID, spacing, 3);
  2109.             ParamText(str, '', '', '');
  2110.             if Frameinterval < 99.0 then
  2111.                 SetDReal(MyLog, IntervalID, Frameinterval, 3)
  2112.             else
  2113.                 SetDReal(MyLog, IntervalID, Frameinterval, 0);
  2114.             SelectDialogItemText(MyLog, SpacingID, 0, 32767);
  2115.             OutlineButton(MyLog, ok, 16);
  2116.             repeat
  2117.                 ModalDialog(nil, item);
  2118.                 if (item >= VolumeID) and (item <= HSVID) then begin
  2119.                     case item of
  2120.                         VolumeID: StackType := VolumeStack;
  2121.                         MovieID: StackType := MovieStack;
  2122.                         rgbID: StackType := rgbStack;
  2123.                         hsvID: StackType := hsvStack;
  2124.                     end;
  2125.                     ShowStackType;
  2126.                   end;
  2127.                 if item = SpacingID then begin
  2128.                     spacing := GetDReal(MyLog, SpacingID);
  2129.                     if SpatiallyCalibrated then
  2130.                         SliceSpacing := spacing * xScale
  2131.                     else
  2132.                         SliceSpacing := spacing;
  2133.                 end;
  2134.                 if item = IntervalID then
  2135.                     Frameinterval := GetDReal(MyLog, IntervalID);
  2136.             until (item = ok) or (item = cancel);
  2137.             DisposeDialog(mylog);
  2138.             if item = cancel then begin
  2139.                 StackType := SaveType;
  2140.                 SliceSpacing := SaveSpacing;
  2141.                 Frameinterval := SaveInterval;
  2142.             end else
  2143.                 if ((StackType = rgbStack) or (StackType = hsvStack)) and (nSlices <> 3) then begin
  2144.                     PutError('RGB and HSV stacks must have three slices.');
  2145.                     StackType := SaveType;
  2146.                 end;
  2147.         end; {with}
  2148.         UpdateTitleBar;
  2149.     end;
  2150.  
  2151.  
  2152. end.